import { EventEmitter } from '../utils/EventEmitter';

/**
 * 二维向量类
 */
export class Vector2 extends EventEmitter {
    public x: number;
    public y: number;
    
    constructor(x: number = 0, y: number = 0) {
        super();
        this.x = x;
        this.y = y;
    }
    
    /**
     * 获取向量的长度
     */
    public get length(): number {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }
    
    /**
     * 获取向量的平方长度
     */
    public get lengthSquared(): number {
        return this.x * this.x + this.y * this.y;
    }
    
    /**
     * 获取向量的单位向量
     */
    public get normalized(): Vector2 {
        const len = this.length;
        if (len === 0) {
            return new Vector2();
        }
        return new Vector2(this.x / len, this.y / len);
    }
    
    /**
     * 克隆向量
     */
    public clone(): Vector2 {
        return new Vector2(this.x, this.y);
    }
    
    /**
     * 设置向量值
     */
    public set(x: number, y: number): Vector2 {
        this.x = x;
        this.y = y;
        this.emit('change', { x, y });
        return this;
    }
    
    /**
     * 向量加法
     */
    public add(v: Vector2): Vector2 {
        this.x += v.x;
        this.y += v.y;
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量减法
     */
    public subtract(v: Vector2): Vector2 {
        this.x -= v.x;
        this.y -= v.y;
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量乘法
     */
    public multiply(scalar: number): Vector2 {
        this.x *= scalar;
        this.y *= scalar;
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量除法
     */
    public divide(scalar: number): Vector2 {
        if (scalar === 0) {
            throw new Error('Cannot divide by zero');
        }
        this.x /= scalar;
        this.y /= scalar;
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量点积
     */
    public dot(v: Vector2): number {
        return this.x * v.x + this.y * v.y;
    }
    
    /**
     * 向量叉积
     */
    public cross(v: Vector2): number {
        return this.x * v.y - this.y * v.x;
    }
    
    /**
     * 计算两个向量之间的距离
     */
    public distance(v: Vector2): number {
        const dx = this.x - v.x;
        const dy = this.y - v.y;
        return Math.sqrt(dx * dx + dy * dy);
    }
    
    /**
     * 计算两个向量之间的平方距离
     */
    public distanceSquared(v: Vector2): number {
        const dx = this.x - v.x;
        const dy = this.y - v.y;
        return dx * dx + dy * dy;
    }
    
    /**
     * 向量归一化
     */
    public normalize(): Vector2 {
        const len = this.length;
        if (len === 0) {
            return this;
        }
        return this.divide(len);
    }
    
    /**
     * 向量旋转
     */
    public rotate(angle: number): Vector2 {
        const cos = Math.cos(angle);
        const sin = Math.sin(angle);
        const x = this.x * cos - this.y * sin;
        const y = this.x * sin + this.y * cos;
        this.x = x;
        this.y = y;
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量缩放
     */
    public scale(v: Vector2): Vector2 {
        this.x *= v.x;
        this.y *= v.y;
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量取反
     */
    public negate(): Vector2 {
        this.x = -this.x;
        this.y = -this.y;
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量取绝对值
     */
    public abs(): Vector2 {
        this.x = Math.abs(this.x);
        this.y = Math.abs(this.y);
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量取最小值
     */
    public min(v: Vector2): Vector2 {
        this.x = Math.min(this.x, v.x);
        this.y = Math.min(this.y, v.y);
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量取最大值
     */
    public max(v: Vector2): Vector2 {
        this.x = Math.max(this.x, v.x);
        this.y = Math.max(this.y, v.y);
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量取整
     */
    public floor(): Vector2 {
        this.x = Math.floor(this.x);
        this.y = Math.floor(this.y);
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量取整
     */
    public ceil(): Vector2 {
        this.x = Math.ceil(this.x);
        this.y = Math.ceil(this.y);
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量取整
     */
    public round(): Vector2 {
        this.x = Math.round(this.x);
        this.y = Math.round(this.y);
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量插值
     */
    public lerp(v: Vector2, t: number): Vector2 {
        this.x = this.x + (v.x - this.x) * t;
        this.y = this.y + (v.y - this.y) * t;
        this.emit('change', { x: this.x, y: this.y });
        return this;
    }
    
    /**
     * 向量比较
     */
    public equals(v: Vector2): boolean {
        return this.x === v.x && this.y === v.y;
    }
    
    /**
     * 向量比较（考虑误差）
     */
    public approximatelyEquals(v: Vector2, epsilon: number = 0.0001): boolean {
        return Math.abs(this.x - v.x) < epsilon && Math.abs(this.y - v.y) < epsilon;
    }
    
    /**
     * 向量转字符串
     */
    public toString(): string {
        return `Vector2(${this.x}, ${this.y})`;
    }
    
    /**
     * 创建零向量
     */
    public static zero(): Vector2 {
        return new Vector2(0, 0);
    }
    
    /**
     * 创建单位向量
     */
    public static one(): Vector2 {
        return new Vector2(1, 1);
    }
    
    /**
     * 创建上向量
     */
    public static up(): Vector2 {
        return new Vector2(0, 1);
    }
    
    /**
     * 创建下向量
     */
    public static down(): Vector2 {
        return new Vector2(0, -1);
    }
    
    /**
     * 创建左向量
     */
    public static left(): Vector2 {
        return new Vector2(-1, 0);
    }
    
    /**
     * 创建右向量
     */
    public static right(): Vector2 {
        return new Vector2(1, 0);
    }
    
    /**
     * 向量加法（静态方法）
     */
    public static add(a: Vector2, b: Vector2): Vector2 {
        return new Vector2(a.x + b.x, a.y + b.y);
    }
    
    /**
     * 向量减法（静态方法）
     */
    public static subtract(a: Vector2, b: Vector2): Vector2 {
        return new Vector2(a.x - b.x, a.y - b.y);
    }
    
    /**
     * 向量乘法（静态方法）
     */
    public static multiply(v: Vector2, scalar: number): Vector2 {
        return new Vector2(v.x * scalar, v.y * scalar);
    }
    
    /**
     * 向量除法（静态方法）
     */
    public static divide(v: Vector2, scalar: number): Vector2 {
        if (scalar === 0) {
            throw new Error('Cannot divide by zero');
        }
        return new Vector2(v.x / scalar, v.y / scalar);
    }
    
    /**
     * 向量点积（静态方法）
     */
    public static dot(a: Vector2, b: Vector2): number {
        return a.x * b.x + a.y * b.y;
    }
    
    /**
     * 向量叉积（静态方法）
     */
    public static cross(a: Vector2, b: Vector2): number {
        return a.x * b.y - a.y * b.x;
    }
    
    /**
     * 向量距离（静态方法）
     */
    public static distance(a: Vector2, b: Vector2): number {
        const dx = a.x - b.x;
        const dy = a.y - b.y;
        return Math.sqrt(dx * dx + dy * dy);
    }
    
    /**
     * 向量平方距离（静态方法）
     */
    public static distanceSquared(a: Vector2, b: Vector2): number {
        const dx = a.x - b.x;
        const dy = a.y - b.y;
        return dx * dx + dy * dy;
    }
    
    /**
     * 向量插值（静态方法）
     */
    public static lerp(a: Vector2, b: Vector2, t: number): Vector2 {
        return new Vector2(
            a.x + (b.x - a.x) * t,
            a.y + (b.y - a.y) * t
        );
    }
    
    /**
     * 向量角度（静态方法）
     */
    public static angle(a: Vector2, b: Vector2): number {
        const dot = Vector2.dot(a, b);
        const det = Vector2.cross(a, b);
        return Math.atan2(det, dot);
    }
    
    /**
     * 向量旋转（静态方法）
     */
    public static rotate(v: Vector2, angle: number): Vector2 {
        const cos = Math.cos(angle);
        const sin = Math.sin(angle);
        return new Vector2(
            v.x * cos - v.y * sin,
            v.x * sin + v.y * cos
        );
    }
    
    /**
     * 向量缩放（静态方法）
     */
    public static scale(a: Vector2, b: Vector2): Vector2 {
        return new Vector2(a.x * b.x, a.y * b.y);
    }
    
    /**
     * 向量取反（静态方法）
     */
    public static negate(v: Vector2): Vector2 {
        return new Vector2(-v.x, -v.y);
    }
    
    /**
     * 向量取绝对值（静态方法）
     */
    public static abs(v: Vector2): Vector2 {
        return new Vector2(Math.abs(v.x), Math.abs(v.y));
    }
    
    /**
     * 向量取最小值（静态方法）
     */
    public static min(a: Vector2, b: Vector2): Vector2 {
        return new Vector2(Math.min(a.x, b.x), Math.min(a.y, b.y));
    }
    
    /**
     * 向量取最大值（静态方法）
     */
    public static max(a: Vector2, b: Vector2): Vector2 {
        return new Vector2(Math.max(a.x, b.x), Math.max(a.y, b.y));
    }
    
    /**
     * 向量取整（静态方法）
     */
    public static floor(v: Vector2): Vector2 {
        return new Vector2(Math.floor(v.x), Math.floor(v.y));
    }
    
    /**
     * 向量取整（静态方法）
     */
    public static ceil(v: Vector2): Vector2 {
        return new Vector2(Math.ceil(v.x), Math.ceil(v.y));
    }
    
    /**
     * 向量取整（静态方法）
     */
    public static round(v: Vector2): Vector2 {
        return new Vector2(Math.round(v.x), Math.round(v.y));
    }
} 